/*
 * Filename	TokenValidataFilter.java
 * @author	zhangFeng
 * @version	1.0.0
 */
package com.zf.spring.microservice.zuul.common.filters.pre;

import io.jsonwebtoken.Claims;

import java.util.ArrayList;
import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.util.UrlPathHelper;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zf.spring.microservice.zuul.common.filters.CustomRouteLocator;
import com.zf.spring.microservice.zuul.common.filters.FilterConfigurationBean;
import com.zf.spring.microservice.zuul.common.token.jwt.JwtTokenProvider;

/**
 * 验证token合法性。
 * 
 * @author zhangFeng
 * @since 1.0.0_Jan 25, 2017
 */
@Component
public class TokenValidataFilter extends ZuulFilter {
	protected static final Logger logger = LoggerFactory
			.getLogger(TokenValidataFilter.class);
	private UrlPathHelper urlPathHelper = new UrlPathHelper();
	@Autowired
	private ServerProperties server;

	@Autowired
	private ZuulProperties zuulProperties;

	JwtTokenProvider jwtTokenProvider;
	FilterConfigurationBean filterConfigurationBean;

	public TokenValidataFilter(JwtTokenProvider jwtTokenProvider,
			FilterConfigurationBean filterConfigurationBean) {
		this.jwtTokenProvider = jwtTokenProvider;
		this.filterConfigurationBean = filterConfigurationBean;
	}

	@Override
	public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		// 根据routeId，排查需要做权限校验的请求
		return !filterConfigurationBean.getNoAuthenticationUrls().contains(
				ctx.get("proxy"));
	}

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		final String requestURI = this.urlPathHelper
				.getPathWithinApplication(ctx.getRequest());
		// 先获取token字段，如果没有，从Authentication获取
		HttpServletRequest request = ctx.getRequest();
		String token = request.getParameter("token");
		if (token == null) {
			token = request.getHeader("Authorization");
		}
		Claims claims = jwtTokenProvider.validataToken(token);
		if (claims == null) {
			forbidden();
		}

		ArrayList<String> urls = (ArrayList<String>) claims.get("scope");
		ZuulRoute[] zuulRoutes = new ZuulRoute[urls.size()];
		for (int i = 0; i < urls.size(); i++) {
			zuulRoutes[i] = new ZuulRoute(urls.get(i), urls.get(i));
		}
		// 此处自定义的原因是想使用zuul自带的url匹配机制
		CustomRouteLocator customRouteLocator = new CustomRouteLocator(
				Arrays.asList(zuulRoutes), server.getServletPrefix(),
				zuulProperties);
		Route matchingRoute = customRouteLocator.getMatchingRoute(requestURI);
		if (matchingRoute == null) {
			forbidden();
		}
		return null;
	}

	@Override
	public String filterType() {
		return "pre";
	}

	@Override
	public int filterOrder() {
		return 6;
	}

	void forbidden() {
		RequestContext.getCurrentContext().setResponseStatusCode(
				HttpStatus.FORBIDDEN.value());
		ReflectionUtils.rethrowRuntimeException(new ZuulException("无访问权限",
				HttpStatus.FORBIDDEN.value(), "token校验不通过"));
	}

}
